<template>
  <div>
    <div class="flex">
      <Title :fontSize="fontSize" title="发票列表" style="margin-bottom: 12px" />
      <span v-if="invoiceEvent && isExamine && isCurrentVersion" class="tip">发票添加后请点击下方【保存】按钮</span>
      <div style="flex: 1;"/>
      <template v-if="showOperator">
        <ImportButton
          :import-api="'/admin/inputInvoice/ocr'"
          :before-prop="true"
          :before-prop-func="beforeUpload"
          :hide-confirm="true"
          :file-size="invoiceFileSize"
          :is-disabled="uploadLoading"
          is-diy
          style="height:30px;"
          accept=".jpg,.jpeg,.png,.pdf,.bmp"
          type="uploadFile"
          @complateSetData="successUpload"
          @onError="errorUpload">
          <div class="flex-center">
            <el-button :loading="uploadLoading" size="small" type="primary" style="padding: 7px">
              上传识别<tipIcon class="upload-tip" content="支持JPG/JPEG/PNG/PDF/BMP五种文件类型的发票识别"/>
            </el-button>
          </div>
        </ImportButton>
        <PlainCreateBtn style="width: 100px;margin-left: 12px;" size="small" @click="addValue">添加</PlainCreateBtn>
        <PlainCreateBtn size="small" @click="openInvoiceDialog">引用已有发票</PlainCreateBtn>
      </template>
    </div>
    <dataDisplay :data-list="dataList" class="top-data" />
    <dynamicEditTable
      ref="dynamicEditTableRef"
      v-model="value"
      :list-data="value"
      :list-setting="listSetting"
      :is-edit="showOperator"
      :show-add-btn="false"
      :current-widthdraw="currentWidthdraw"
      can-empty
      open-page
      is-supplier
      @changeValue="changeValue"
      @inputChange="inputChange"
      @onRowDel="onRowDel"
      @toEdit="toEdit"/>
    <quoteInvoice ref="quoteInvoiceRef" @quoteInvoice="quoteInvoice"/>
  </div>
</template>

<script>
import Title from '@/components/Title';
import dynamicEditTable from '@/components/Common/dynamicEditTable';
import dataDisplay from '@/components/Common/baseComponent/dataDisplay';
import quoteInvoice from '@/components/SupplierComponent/quoteInvoice';
import ImportButton from '@/components/ImportButton';
import { moneyFilter } from '@/filters/number';
import chargeoffiIcon from '@/assets/chargeOffDetail/chargeoff_status.png';
import math from '@/utils/math';
import { getFitInvoiceList } from '@/api/inputInvoice';
const associatedKeys = ['invoiceNumber', 'invoicePrice'];
export default {
  components: { Title, dynamicEditTable, dataDisplay, quoteInvoice, ImportButton },
  model: {
    prop: 'value',
    event: 'changeValue'
  },
  props: {
    value: {
      type: Array,
      default: () => {
        return [{}];
      }
    },
    isEdit: {
      type: Boolean,
      default: false
    },
    // 发票事件开启后才可编辑，默认开启
    invoiceEvent: {
      type: Boolean,
      default: true
    },
    fontSize: {
      type: String,
      default: '16px'
    },
    isCreator: { // 是否为发起人
      type: Boolean,
      default: false
    },
    pageFrom: {
      type: String,
      default: '' // 父级页面是否是详情 detail
    },
    currentWidthdraw: { // 当前选中的审批记录
      type: Object,
      default: () => {
        return {
          id: 0,
          examineStatus: 2
        };
      }
    },
    isCurrentVersion: {// 是否当前版本
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      chargeoffiIcon,
      listSetting: [
        { label: '发票代码', width: '140px', type: 'inputPureNumber', maxlength: 20, isRequired: true, keyword: 'invoiceCode', placeholder: '限20位数', linkDisabled: 'inputInvoiceId', associatedKeys, associatedKeysValidCallback: this.associatedKeysValidCallback },
        { label: '发票号码', width: '140px', type: 'inputText', maxlength: 20, isRequired: true, keyword: 'invoiceNumber', placeholder: '限20位数', linkDisabled: 'inputInvoiceId', needTrim: true, renderType: 'voiceLink' },
        { label: '含税金额(元)', type: 'inputNumber', tip: '提示：请填写发票上的金额', width: '145px', isRequired: true, keyword: 'invoicePrice', placeholder: '保留2位小数', linkDisabled: 'inputInvoiceId' },
        { label: '不含税金额(元)', type: 'associatedSubtract', width: '125px', disabled: true, keyword: 'excludeTaxPrice', placeholder: '保留2位小数', subtractKey: ['invoicePrice', 'tax'], linkDisabled: 'inputInvoiceId' },
        { label: '税额(元)', type: 'inputNumber', tip: '提示：请填写发票上的金额', width: '125px', isRequired: true, keyword: 'tax', placeholder: '保留2位小数', associatedKeys, linkDisabled: 'inputInvoiceId', associatedKeysValidCallback: this.associatedKeysValidCallback },
        {
          label: '发票类型', type: 'select', renderType: 'filter',
          isRequired: true, width: '120px', keyword: 'invoiceType',
          default: 0, options: [
            { id: 0, name: '纸质专票' }, { id: 1, name: '纸质普票' }, { id: 2, name: '电子专票' },
            { id: 3, name: '电子普票' }, { id: 4, name: '其他票据' }
          ], associatedKeys, linkDisabled: 'inputInvoiceId',
          associatedKeysValidCallback: this.associatedKeysValidCallback
        },
        { label: '发票项目', width: '140px', type: 'inputText', maxlength: 100, isRequired: true, keyword: 'invoiceProject', placeholder: '限100个字符', associatedKeys, linkDisabled: 'inputInvoiceId', associatedKeysValidCallback: this.associatedKeysValidCallback },
        { label: '开票日期', keyword: 'invoiceDate', width: '150px', type: 'datepicker', isRequired: true,
          pickerOptions: {
            disabledDate: (time) => {
              const nowDay = new Date(new Date().setHours(0, 0, 0, 0));
              return time.getTime() > nowDay;
            }
          }, associatedKeys, linkDisabled: 'inputInvoiceId',
          associatedKeysValidCallback: this.associatedKeysValidCallback
        },
        {
          label: '发票状态', type: 'onlyRead', renderType: 'filter',
          width: '120px', keyword: 'invoiceStatus',
          options: [
            { id: 0, name: '执行中' }, { id: 1, name: '待认证' }, { id: 2, name: '认证中' },
            { id: 3, name: '已完成' }
          ], associatedKeys, disabled: true,
          associatedKeysValidCallback: this.associatedKeysValidCallback
        },
        { label: '附件', type: 'attachment', width: '180px', keyword: 'attachment', associatedKeys, linkDisabled: 'inputInvoiceId', disableFieldNeedValueBefore: true, associatedKeysValidCallback: this.associatedKeysValidCallback },
        { label: '关联审批', type: 'withdraws', keyword: 'withdraws', width: '150px', linkDisabled: 'inputInvoiceId' }
      ],
      noticeInvoices: [], // 同一发票号码只提示一次（识别除外）
      totalInvoiceAmount: 0,
      totalExcludeTaxPrice: 0,
      totalTaxAmount: 0,
      uploadLoading: false,
      invoiceFileSize: 0
    };
  },
  computed: {
    showOperator() {
      return this.invoiceEvent && (this.isEdit || this.isExamine) && this.isCurrentVersion;
    },
    isExamine() {
      return this.pageFrom === 'detail' && (this.currentWidthdraw.examineStatus === 0 || this.currentWidthdraw.examineStatus === 1);
    },
    dataList() {
      return [
        { icon: chargeoffiIcon, label: '含税金额', data: this.moneyFilter(this.totalInvoiceAmount, true, '', true), unit: '元' },
        { icon: chargeoffiIcon, label: '不含税金额', data: this.moneyFilter(this.totalExcludeTaxPrice, true, '', true), unit: '元' },
        { icon: chargeoffiIcon, label: '税额', data: this.moneyFilter(this.totalTaxAmount, true, '', true), unit: '元' }
      ];
    },
    fieldsMap() {
      return {
        invoice_code: { key: 'invoiceCode', type: 'string' },
        invoice_no: { key: 'invoiceNumber', type: 'string' },
        total_price_and_tax: { key: 'invoicePrice', type: 'money' },
        total_price: { key: 'excludeTaxPrice', type: 'money' },
        total_tax: { key: 'tax', type: 'money' },
        invoice_date: { key: 'invoiceDate', type: 'date' }
      };
    }
  },
  watch: {
    value: {
      handler: function(val) {
        this.getTotalAmount();
      },
      immediate: true
    }
  },
  mounted() {
    if (this.isEdit && this.value.length === 0) {
      this.$emit('changeValue', [{}]);
    } else {
      this.changeValue(this.value);
    }
  },
  methods: {
    moneyFilter,
    addValue() {
      this.$refs['dynamicEditTableRef'].addValue();
    },
    openInvoiceDialog() {
      this.$refs['quoteInvoiceRef'].openDialog();
    },
    toEdit(scope) {
      const url = this.$router.resolve({
        name: 'inputInvoiceDetail',
        query: { id: scope.row.inputInvoiceId }
      });
      window.open(url.href, '_blank');
    },
    getFitArr(list = []) {
      list.map(item => {
        item.attachment = item.attachmentUrlStr ? JSON.parse(item.attachmentUrlStr)[0] : null;
        item.invoiceDate = item.invoiceDate * 1000;
        item.invoiceNumber = item.invoiceNo;
        item.tax = item.taxAmount;
        item.excludeTaxPrice = item.money;
        item.inputInvoiceId = item.id;
        item.id = '';
      });
    },
    quoteInvoice(list = []) {
      this.getFitArr(list);
      const value = this.value.concat(list);
      this.$emit('changeValue', value);
      this.$nextTick(() => {
        this.changeValue(value);
      });
    },
    async inputChange({ key, data, index }) {
      const { invoiceNumber, invoicePrice } = data;
      if (!associatedKeys.includes(key)) return;
      const keys = associatedKeys;
      const isEmptyArr = [];
      keys.forEach(key => {
        if (data[key] || data[key] === 0) {
          isEmptyArr.push(false);
        } else {
          isEmptyArr.push(true);
        }
      });
      delete data._systemInvoicePrice;
      if (isEmptyArr.every(i => i === false) && keys.includes(key)) {
        const res = await getFitInvoiceList({ invoiceNo: invoiceNumber });
        if (res.code === 200 && res.data && res.data.length) {
          const systemInvoice = res.data[0];
          // 含税金额与系统中的不一致，提示修改，不回填系统存在的发票信息
          // 只有发票号码和含税金额都与系统中先有得发票一致时，才回填系统中已存在的发票信息
          if (Number(invoicePrice) !== Number(systemInvoice.invoicePrice)) {
            data._systemInvoicePrice = Number(systemInvoice.invoicePrice);
            if (!this.noticeInvoices.includes(invoiceNumber)) {
              this.$confirm(`已存在发票号码为【${invoiceNumber}】的发票，但“含税金额”不一致，请修改或向财务反馈`, '', {
                confirmButtonText: '确定',
                showCancelButton: false,
                type: 'warning',
                showClose: false,
                center: true,
                dangerouslyUseHTMLString: true,
                iconClass: 'charge-icon',
                customClass: 'del-message'
              });
              this.noticeInvoices.push(invoiceNumber);
            }
          } else {
            this.getFitArr(res.data);
            this.$set(this.value, index, res.data[0]);
            this.$emit('changeValue', this.value);
          }
        }
        // 为了触发表格发票号码和含税金额的一致性校验
        data.invoiceNumber = null;
        data.invoiceNumber = invoiceNumber;
      }
    },
    associatedKeysValidCallback(data) {
      return data.hasOwnProperty('_systemInvoicePrice') && data._systemInvoicePrice !== data.invoicePrice;
    },
    validate() {
      return this.$refs.dynamicEditTableRef.validate();
    },
    changeValue(value) {
      if (value && value.length) {
        value.forEach((item, index) => {
          if (item.invoiceType && (item.invoiceType === 2 || item.invoiceType === 3)) {
            this.rowExtendRequired(index, ['attachment']);
            this.$set(item, '_toolTip', '请检查所上传的电子发票是否有加盖“发票章”，如没有请联系对方提供“OFD版”即电子发票格式为“.OFD”，再进行上传。');
          } else {
            this.rowExtendRequired(index);
            this.$set(item, '_required', false);
            this.$set(item, '_toolTip', '');
          }
        });
      }
      this.getTotalAmount();
      this.$emit('changeValue', value);
    },
    rowExtendRequired(index = -1, extendRequiredKeys = []) {
      if (index === -1) return;
      this.$set(this.value[index], 'extendRequiredKeys', extendRequiredKeys);
    },
    getTotalAmount() {
      let res1 = 0;
      let res2 = 0;
      let res3 = 0;
      if (this.value && this.value.length > 0) {
        res1 = this.value.reduce((total, current) => {
          return math.add(total, Number(current.invoicePrice || 0));
        }, 0);
        this.totalInvoiceAmount = res1.toFixed(2) || 0;
        res2 = this.value.reduce((total, current) => {
          return math.add(total, Number(current.excludeTaxPrice || 0));
        }, 0);
        this.totalExcludeTaxPrice = res2.toFixed(2) || 0;
        res3 = this.value.reduce((total, current) => {
          return math.add(total, Number(current.tax || 0));
        }, 0);
        this.totalTaxAmount = res3.toFixed(2) || 0;
      } else {
        this.totalInvoiceAmount = 0;
        this.totalExcludeTaxPrice = 0;
        this.totalTaxAmount = 0;
      }
    },
    onRowDel(val) {
      this.$emit('onRowDel', val);
    },
    beforeUpload(file) {
      if (this.uploadLoading) {
        return Promise.reject();
      }
      if (file) {
        this.uploadLoading = true;
        this.invoiceFileSize = file.size;
        const res = /\.jpe?g$|\.png$|\.pdf$|\.bmp$/i.test(file.name);
        if (!res) {
          this.uploadLoading = false;
          this.$message.warning('请注意只能上传【jpg/jpeg/png/pdf/bmp】类型文件！');
          return Promise.reject();
        }
      }
    },
    async successUpload(invoiceFile) {
      this.uploadLoading = false;
      if (invoiceFile.data && invoiceFile.data.vat_invoices && invoiceFile.data.vat_invoices.length && invoiceFile.data.vat_invoices[0] && invoiceFile.data.vat_invoices[0].entities) {
        const identifyResult = invoiceFile.data.vat_invoices[0].entities;
        const invoiceInfo = this.getInvoiceInfo(identifyResult, invoiceFile.data.attachment);
        if (invoiceFile.data.attachment) {
          this.$emit('attachmentAdd', invoiceFile.data.attachment);
        }
        if (!invoiceInfo.invoiceNumber) {
          this.$message.warning('无法识别发票号码，请手动输入');
        } else {
          const res = await getFitInvoiceList({ invoiceNo: invoiceInfo.invoiceNumber });
          // 若发票号码已存在系统进项发票中
          if (res.code === 200 && res.data && res.data.length) {
            const systemInvoice = res.data[0];
            // 含税金额与系统中的不一致，提示修改，不回填系统存在的发票信息
            // 只有发票号码和含税金额都与系统中先有得发票一致时，才回填系统中已存在的发票信息
            if (Number(invoiceInfo.invoicePrice) !== Number(systemInvoice.invoicePrice)) {
              invoiceInfo._systemInvoicePrice = Number(systemInvoice.invoicePrice);
              this.$confirm(`已存在发票号码为【${invoiceInfo.invoiceNumber}】的发票，但“含税金额”不一致，请修改或向财务反馈`, '', {
                confirmButtonText: '确定',
                showCancelButton: false,
                type: 'warning',
                showClose: false,
                center: true,
                dangerouslyUseHTMLString: true,
                iconClass: 'charge-icon',
                customClass: 'del-message'
              });
            } else {
              // 若发票号码和含税金额均和系统中已有发票匹配，则回填上传的文件到附件
              if (Array.isArray(res.data) && res.data.length) {
                if (!res.data[0].attachmentUrlStr && invoiceFile.data.attachment) {
                  res.data[0].attachmentUrlStr = JSON.stringify([invoiceFile.data.attachment]);
                }
              }
              this.quoteInvoice(res.data);
              return;
            }
          }
        }
        this.setInvoiceInfo(invoiceInfo);
      }
    },
    // 回填上传的发票信息
    setInvoiceInfo(invoiceInfo) {
      this.value.push(invoiceInfo);
      this.$emit('changeValue', this.value);
      this.$refs['dynamicEditTableRef'].errorIds = [];
      this.$forceUpdate();
    },
    // 获取识别数据，转换成表单数据
    getInvoiceInfo(invoiceData, attachment = []) {
      const currInvoiceInfo = {};
      for (let i = 0; i < invoiceData.length; i++) {
        const typeData = this.fieldsMap[invoiceData[i].type];
        const value = invoiceData[i].value || null;
        if (typeData && value) {
          if (typeData.type === 'string') {
            currInvoiceInfo[typeData.key] = value;
          } else if (typeData.type === 'money') {
            // 不能截取第一个字符,因为飞书ocr识别有些会返回¥,有些不会返回
            // const temp = data.value.slice(1);
            // 不用替换第一个字符,因为飞书识别返回的金额符号不是标准的
            // const temp = data.value.replace(/^¥|^Ұ|^￥/, '');
            const temp = value.match(/\d+\.?\d+/);
            if (temp) {
              currInvoiceInfo[typeData.key] = Number(temp[0]);
            }
          } else if (typeData.type === 'date') {
            // 提取年、月、日
            const match = value.match(/(\d{4})年(\d{2})月(\d{2})日/);
            const date = new Date(parseInt(match[1]), parseInt(match[2]) - 1, parseInt(match[3]));
            currInvoiceInfo[typeData.key] = date.getTime();
          }
        }
      }
      currInvoiceInfo.invoiceType = null;
      currInvoiceInfo.invoiceStatus = null;
      currInvoiceInfo.withdraws = null;
      currInvoiceInfo.invoiceProject = '';
      currInvoiceInfo.attachment = null;
      if (Array.isArray(attachment) && attachment.length) {
        currInvoiceInfo.attachment = attachment[0];
      }
      return currInvoiceInfo;
    },
    errorUpload(val) {
      this.uploadLoading = false;
      this.$message.error(val);
    }
  }
};
</script>

<style lang="scss" scoped>
.flex {
  display: flex;
  align-items: center;
}
.top-data {
  &::v-deep {
    .data-item {
      flex-basis: 30%;
    }
  }
}
.tip {
  font-size: 12px;
  color: #F56C6C;
  margin-left: 15px;
}
.upload-tip {
  vertical-align: top;
  filter: brightness(2);
  margin-left: 5px;
  &:hover {
    filter: brightness(999) !important;
  }
}
</style>
